package qc.module.qms.service.exchange;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.enums.DataManagementTypeEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.DateUtil;
import qc.common.core.utils.IdentifierUtil;
import qc.module.qms.dto.exchange.log.DataExchangeLogDto;
import qc.module.qms.dto.exchange.log.DataExchangeLogQueryConditionDto;
import qc.module.qms.entity.ExchangeLog;
import qc.module.qms.mapper.ExchangeLogMapper;
import qc.module.qms.repository.ExchangeLogRepository;

import java.util.Date;
import java.util.List;

/**
 * 数据交换日志Service
 *
 * @author QuCheng Tech
 * @since 2024/9/25
 */
@Service
public class ExchangeLogService {
    private ExchangeLogRepository repository;

    @Autowired
    public void setRepository(ExchangeLogRepository repository) {
        this.repository = repository;
    }

    /***
     * 查询数据交换日志
     *
     * @param condition 查询条件
     * @return java.util.List<qc.module.qms.dto.exchange.log.DataExchangeLogDto>
     * @author QuCheng Tech
     * @since 2024/9/25
     */
    public List<DataExchangeLogDto> queryLogs(DataExchangeLogQueryConditionDto condition) throws QCPromptException {
        if (condition == null)
            throw new QCPromptException("查询数据交换日志对象不能为空");
        if (condition.getCid() < 0x1)
            throw new QCPromptException("查询数据交换日志交换数据分类ID不能为空");
        if (StringUtils.isBlank(condition.getStcd()))
            throw new QCPromptException("查询数据交换日志站点编码不能为空");
        if (StringUtils.isBlank(condition.getBegintm()))
            throw new QCPromptException("查询数据交换日志数据起始时间不能为空");
        if (StringUtils.isBlank(condition.getEndtm()))
            throw new QCPromptException("查询数据交换日志数据截止时间不能为空");
        Date beginTime = DateUtil.parseDate(condition.getBegintm());
        if (beginTime == null)
            throw new QCPromptException("查询数据交换日志数据起始时间无法转换为有效的时间格式");
        Date endTime = DateUtil.parseDate(condition.getEndtm());
        if (endTime == null)
            throw new QCPromptException("查询数据交换日志数据截止时间无法转换为有效的时间格式");
        if (beginTime.after(endTime))
            throw new QCPromptException("查询数据交换日志数据起始时间不能大于截止时间");

        LambdaQueryWrapper<ExchangeLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExchangeLog::getCid, condition.getCid());
        wrapper.eq(ExchangeLog::getStcd, condition.getStcd());
        //时间均按照操作的时间，即写入时间
        wrapper.ge(ExchangeLog::getIntm, beginTime);
        wrapper.le(ExchangeLog::getIntm, endTime);
        //判断人工操作还是自动
        if (condition.getIsmanual() == 0x1) {
            //人工操作
            wrapper.eq(ExchangeLog::getIsmanual, true);
        } else if (condition.getIsmanual() == 0x2) {
            //自动操作
            wrapper.eq(ExchangeLog::getIsmanual, false);
        }
        //判断操作类型，生成写入、修改、删除
        if (condition.getOptype() == DataManagementTypeEnum.INSERT.getIndex()) {
            wrapper.eq(ExchangeLog::getOptype, DataManagementTypeEnum.INSERT);
        } else if (condition.getOptype() == DataManagementTypeEnum.UPDATE.getIndex()) {
            wrapper.eq(ExchangeLog::getOptype, DataManagementTypeEnum.UPDATE);
        } else if (condition.getOptype() == DataManagementTypeEnum.DELETE.getIndex()) {
            wrapper.eq(ExchangeLog::getOptype, DataManagementTypeEnum.DELETE);
        }
        //判断执行结果，成功、失败
        if (condition.getExecresult() == 0x1) {
            //执行成功
            wrapper.eq(ExchangeLog::getExecresult, 0b11);
        } else if (condition.getExecresult() == 0x2) {
            //执行失败
            wrapper.eq(ExchangeLog::getExecresult, 0b01);
        }
        //判断关键字，匹配sql和执行信息
        if (StringUtils.isNotBlank(condition.getKeywords())) {
            wrapper.like(ExchangeLog::getSqlstr, condition.getKeywords()).or().like(ExchangeLog::getExecinfo, condition.getKeywords());
        }

        //排序，按写入时间降序
        wrapper.orderByDesc(ExchangeLog::getIntm);

        //查询数据
        List<ExchangeLog> ens = repository.selectList(wrapper);
        if (ens != null && ens.size() > 0x0) {
            return ExchangeLogMapper.MAPPER.toDtoList(ens);
        }

        return null;
    }

    /***
     * 添加日志，添加人工操作日志和定时任务自动执行日志。
     * 将人工操作加入到日志表，由后台定时任务自动进行执行
     *
     * @param dto
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2024/9/25
     */
    public String addLog(DataExchangeLogDto dto) {
        //判断输入：数据分类ID、站点编码、起止时间是必须有
        if (dto == null)
            return QCUnifyReturnValue.Warn("添加数据交换日志对象不能为空");
        if (dto.getCid() < 0x1)
            return QCUnifyReturnValue.Warn("添加数据交换日志交换数据分类ID不能为空");
        if (StringUtils.isBlank(dto.getStcd()))
            return QCUnifyReturnValue.Warn("添加数据交换日志站点编码不能为空");
        if (StringUtils.isBlank(dto.getBegintm()))
            return QCUnifyReturnValue.Warn("添加数据交换日志数据起始时间不能为空");
        if (StringUtils.isBlank(dto.getEndtm()))
            return QCUnifyReturnValue.Warn("添加数据交换日志数据截止时间不能为空");
        Date beginTime = DateUtil.parseDate(dto.getBegintm());
        if (beginTime == null)
            return QCUnifyReturnValue.Warn("添加数据交换日志数据起始时间无法转换为有效的时间格式");
        Date endTime = DateUtil.parseDate(dto.getEndtm());
        if (endTime == null)
            return QCUnifyReturnValue.Warn("添加数据交换日志数据截止时间无法转换为有效的时间格式");
        if (beginTime.after(endTime))
            return QCUnifyReturnValue.Warn("添加数据交换日志数据起始时间不能大于截止时间");

        Date now = DateUtil.getNowDate();
        //初始化Entity
        ExchangeLog en = new ExchangeLog();
        en.setLogid(IdentifierUtil.randomUUID());
        en.setIntm(now);
        en.setIsmanual(false);//默认为都是自动任务
        en.setOptype(DataManagementTypeEnum.INSERT);//默认都是生成数据写入
        en.setExecresult(0x0);//默认执行结果是未执行

        //使用dto中的信息进行赋值
        //如果dto中指定了id，使用dto中传入的id
        if (StringUtils.isNotBlank(dto.getLogid()))
            en.setLogid(dto.getLogid());
        en.setCid(dto.getCid());
        en.setStcd(dto.getStcd());
        en.setBegintm(beginTime);
        en.setEndtm(endTime);
        //如果是人工操作，设置操作人名称
        if (dto.isIsmanual()) {
            en.setIsmanual(true);
            en.setUsername(dto.getUsername());
        }
        //操作类型
        DataManagementTypeEnum optype = getDataManagementTypeEnum(dto.getOptype());
        if (optype == DataManagementTypeEnum.UPDATE || optype == DataManagementTypeEnum.DELETE) {
            en.setOptype(optype);
            //如果是修改或删除操作对SQL进行赋值
            en.setSqlstr(dto.getSqlstr());
        }
        //执行结果
        if (dto.getExecresult() > 0x0) {
            en.setExecresult(dto.getExecresult());
            en.setExecinfo(dto.getExecinfo());
            //执行的时间如果无法正确转换，默认设置为当前时间
            en.setExectm(now);
            if (StringUtils.isNotBlank(dto.getExectm())) {
                Date exectm = DateUtil.parseDate(dto.getExectm());
                if (exectm != null)
                    en.setExectm(exectm);
            }
        }

        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("添加数据交换日志失败");

        return QCUnifyReturnValue.Success();
    }

    static DataManagementTypeEnum getDataManagementTypeEnum(Integer index) {
        if (index != null && index > 0x0) {
            for (DataManagementTypeEnum item : DataManagementTypeEnum.values()) {
                if (item.getIndex() == index) {//判断序号使用getIndex，判断内容使用getName
                    return item;
                }
            }
        }
        return DataManagementTypeEnum.INSERT;
    }

    /***
     * 设置指定日志ID的执行结果
     *
     * @param logid 日志ID
     * @param isSuccess 是否执行成功
     * @param info 执行信息
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2024/9/25
     */
    public String setExecuteResult(String logid, boolean isSuccess, String info) {
        if (StringUtils.isBlank(logid))
            return QCUnifyReturnValue.Warn("设置数据交换日志执行结果的日志ID不能为空");

        LambdaUpdateWrapper<ExchangeLog> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ExchangeLog::getLogid, logid);
        //执行结果设置：表示是否执行和执行是否成功，低1位表示是否执行，高1为表示是否成功
        if (isSuccess)
            wrapper.set(ExchangeLog::getExecresult, 0b11);
        else
            wrapper.set(ExchangeLog::getExecresult, 0b01);
        wrapper.set(ExchangeLog::getExectm, DateUtil.getNowDate());
        wrapper.set(ExchangeLog::getExecinfo, info);

        repository.update(null, wrapper);

        return QCUnifyReturnValue.Success();
    }

    /***
     * 取消指定日志ID的执行
     *
     * @param logid 日志ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2024/9/25
     */
    public String cancel(String logid) {
        if (StringUtils.isBlank(logid))
            return QCUnifyReturnValue.Warn("取消数据交换日志执行的日志ID不能为空");

        LambdaUpdateWrapper<ExchangeLog> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ExchangeLog::getLogid, logid);
        //要求交换数据操作时人工操作，并且状态时未执行
        wrapper.eq(ExchangeLog::getIsmanual, true);
        wrapper.eq(ExchangeLog::getExecresult, 0b0);
        //执行结果设置：第3高位为1表示取消
        wrapper.set(ExchangeLog::getExecresult, 0b100);
        wrapper.set(ExchangeLog::getExectm, DateUtil.getNowDate());

        repository.update(null, wrapper);

        return QCUnifyReturnValue.Success();
    }

    /***
     * 获取待执行的人工操作日志记录，自动的由系统中的定时任务创建并执行（不需要单独的查询获取操作）
     *
     * @param cid 数据分类ID，每种不同的数据分类可能需要频次不同，分为不同的定时任务进行处理；传为小于1的值时表示获取全部数据分类
     * @param count 一次获取的记录数量
     * @return java.util.List<qc.module.qms.entity.ExchangeLog>
     * @author QuCheng Tech
     * @since 2024/9/25
     */
    public List<ExchangeLog> getNeedExecuteManualLogs(int cid, int count) {
        LambdaQueryWrapper<ExchangeLog> wrapper = new LambdaQueryWrapper<>();
        //如果指定有效的数据分类，根据指定的数据分类进行查询
        if (cid >= 0x1)
            wrapper.eq(ExchangeLog::getCid, cid);
        //只查询人工，状态为未执行的
        wrapper.eq(ExchangeLog::getIsmanual, true);
        wrapper.eq(ExchangeLog::getExecresult, 0x0);
        //排序，按写入时间升序，写入在前的先进行处理
        wrapper.orderByAsc(ExchangeLog::getIntm);
        //限制数量
        if (count > 0x0)
            wrapper.last("limit " + count);

        //查询数据
        List<ExchangeLog> ens = repository.selectList(wrapper);

        return ens;
    }
}
